<?php
///////////////////////////////////////////////////////////////////////////////////////////////////////
//  这个文件是 JCAT PHP框架的一部，该项目和此文件 均遵循 GNU 自由软件协议
// 
//  Copyleft 2008 JeCat.cn(http://team.JeCat.cn)
//
//
//  JCAT PHP框架 的正式全名是：Jellicle Cat PHP Framework。
//  “Jellicle Cat”出自 Andrew Lloyd Webber的音乐剧《猫》（《Prologue:Jellicle Songs for Jellicle Cats》）。
//  JCAT 是一个开源项目，它像音乐剧中的猫一样自由，你可以毫无顾忌地使用JCAT PHP框架。JCAT 由中国团队开发维护。
//  正在使用的这个版本是：0.6.0 / SVN信息: $Id: funcs.Global.php 2147 2009-12-16 03:14:37Z alee $
//
//
//
//  相关的链接：
//    [主页] http://jcat.JeCat.cn
//    [下载(HTTP)] http://code.google.com/p/jcat-php/downloads/list
//    [下载(svn)] svn checkout http://jcat-php.googlecode.com/svn/branches/0.4.0/Framework/ JCAT0.4
//    [在线文档] http://jcat.JeCat.cn/document
//    [社区] http://jj.jecat.cn/forum-7-1.html
//  不很相关：
//    [MP3] http://www.google.com/search?q=jellicle+songs+for+jellicle+cats+Andrew+Lloyd+Webber
//    [VCD/DVD] http://www.google.com/search?q=CAT+Andrew+Lloyd+Webber+video
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
/*-- Project Introduce --*/
namespace JCAT ;

use JCAT\Core\Assert ;

/**
 * 结构化输出 一个变量
 * 
 * @access	public
 * @param	$Var				mixed	输出的变量
 * @param	$bOutAtOnce=true	bool	是否立即输出
 * @return	string
 */
function PrintVar( $Var, $bOutAtOnce=true ) 
{
	// 特殊值
	if($Var===false)
	{
		$Var = 'false' ;
	}
	else if($Var===true)
	{
		$Var = 'true' ;
	}
	else if($Var===null)
	{
		$Var = 'null' ;
	}

	$sOut = print_r($Var,true) ;
	
	if( $bOutAtOnce )
	{
		print $sOut ;
	}

	return $sOut ;
}


/**
 * 测试执行流程的函数
 *   如果 t() 没有给参数，则简单 输出/返回  t() 的调用次数 ；
 *   如果 传入参数，则依次调用  JCAT_Global::PrintVar() 输出所传入的参数
 *
 * @return	int
 */
function t()
{
	
	// 无参数
	if( func_num_args()==0 )
	{
		static $__oOtlaaltOo__ = 0;
		t( 't(): '.++$__oOtlaaltOo__ ) ;
		return $__oOtlaaltOo__ ;
	}
	
	// 输出参数
	$arrArgv = func_get_args() ;
	$sOut = '' ;
	foreach ($arrArgv as $Item)
	{
		$sItem = '<pre>' ;
		$sItem.= PrintVar($Item) ;
		$sItem.= "</pre>\r\n" ;
		
		print $sItem ;
		
		$sOut.= $sItem ;
	}
	
	// 释放输出缓存
	flush();
	return $sOut ;
}








/**
 * 将一个数组整理成 url的query 部分
 * 
 * @access	public
 * @param	$arrVar			array	待整理的数组变量
 * @param	$sVarName=null	string	数组变量的名称
 * @return	string
 */
function Array2UrlQeruy(  array $arrVar,  $sVarName=null ) 
{
	$arrRet = array() ;
	foreach ($arrVar as $sKey=>$Item)
	{
		if($sVarName===null)
		{
			$sKeyName = $sKey ;
		}
		else
		{
			$sKeyName = $sVarName."%5B{$sKey}%5D" ;
		}
		
		if( is_scalar($Item) )
		{
			$arrRet[] = $sKeyName.'='.urlencode($Item) ;
		}
			
		elseif( is_array($Item) )
		{
			$arrRet[] = Array2UrlQeruy($Item,$sKeyName) ;
		}
	}
	
	return implode('&',$arrRet) ;
}


/**
 * 将当前请求的Request参数 整理成一个可用于 url 的字串返回
 * 
 * @param	$bPost=false			bool
 * @return	string
 */
function Request2UrlQeruy($bPost=false) 
{
	$sRet = JCAT_Global::Array2UrlQeruy( $_GET ) ;
	
	if($bPost)
	{
		$sPostQuery = JCAT_Global::Array2UrlQeruy( $_POST ) ;
		if($sPostQuery)
		{
			$sRet.= $sPostQuery ;
		}
	}
	
	return $sRet ;
}

/**
 * 检查是否为同一个 callback
 *
 * @param	$CallbackA		callback
 * @param	$CallbackB		callback
 * @return	bool
 */
function IsSameCallback($CallbackA,$CallbackB)
{
	
	Assert\IS_THESE($CallbackA,array('callback')) ;
	Assert\IS_THESE($CallbackB,array('callback')) ;
	
	
	if( is_array($CallbackA) )
	{
		if( is_array($CallbackB) )
		{
			return ($CallbackA[0]===$CallbackB[0])
				and ( strtolower($CallbackA[1])===strtolower($CallbackB[1]) ) ;
		}
		
		else 
		{
			return false ;
		}
	}
	
	else
	{
		return strtolower($CallbackA) === strtolower($CallbackB) ;
	}
}

/**
 * 格式化输出
 * 根据项目类型（CommandLine,Desktop,Html） 和  服务器字符集 整理输出内容
 * 
 * @param	$Content	mixed	输出内容
 * @return	string
 */
function FormatOut($Content)
{
	// 留待处理 ... ...
	$sContent = print_r($Content,true) ;
	
	switch( JCAT::$TYPE )
	{
		case JCAT::TYPE_HTML :
			print '<pre>'.$sContent.'</pre>' ;
			break ;
		
		case JCAT::TYPE_COMMANDLINE :
			print JCAT::CharsetToServer($sContent) ;
			break ;
		
		case JCAT::TYPE_DESKTOP :
			print JCAT::CharsetToServer($sContent) ;
			break ;
		
		default :
			JCAT_ASSERT::ASSERT_(0,'?!') ;
			break ;
	}
	
}


/**
 * JCAT_Global::FormatOut() 的别名
 * 
 * @param	$Content	mixed	输出内容
 * @return	string
 */
function FO($Content)
{ return FormatOut($Content) ; }


/**
 * 为函数或 类的静态方法取一个别名
 * 
 * @param	$sAlias				string		函数的新别名
 * @param	$OriginalFunction	callback	函数
 * @return	void
 */
function MakeFunctionAlias($sAlias,$OriginalFunction)
{
	if( is_callable($OriginalFunction) )
	{
		if( function_exists($sAlias) )
		{
			throw new JCAT_Exception("同名的全局函数：“$sAlias”已经定义！",JCAT_Exception::MakeExceptionCode(__CLASS__,4)) ;
		}
		
		// 整理 原函数名
		if( is_array($OriginalFunction) )
		{
			if( is_object($OriginalFunction[0]) )
			{
				throw new JCAT_Exception('参数 $OriginalFunction 只能是 全局函数或类的静态方法',JCAT_Exception::MakeExceptionCode(__CLASS__,5)) ;
			}
			
			$OriginalFunction = "array('{$OriginalFunction[0]}','{$OriginalFunction[1]}')" ;
		}
		else
			$OriginalFunction = "'{$OriginalFunction}'" ;
		
		// 创建别名函数
		eval("function {$sAlias}(){ \$arrArgvs = func_get_args(); \$Ret = call_user_func_array({$OriginalFunction} ,\$arrArgvs); return \$Ret; }") ;
	}
	else
	{
		throw new JCAT_Exception('参数 $OriginalFunction 未定义，$OriginalFunction 必须是一个已定义的函数或类的静态方法。',JCAT_Exception::MakeExceptionCode(__CLASS__,6)) ;		
	}
}

/**
 * 为已定义的类取一个别名
 * 
 * @param	$sAlias			string	类的新别名
 * @param	$sOriginalClass	string	原始类名
 * @return	void
 */
function MakeClassAlias($sAlias,$sOriginalClass)
{echo ',' ;
	if( !class_exists($sOriginalClass) )
	{
		throw new JCAT_Exception("类 {$sOriginalClass} 尚未定义，无法为不存在的类创建别名。",JCAT_Exception::MakeExceptionCode(__CLASS__,7)) ;
	}
	if( class_exists($sAlias) )
	{
		throw new JCAT_Exception("名为 {$sAlias} 的类已经存在，无法用作别名。",JCAT_Exception::MakeExceptionCode(__CLASS__,8)) ;
	}

	eval("class {$sAlias} extends {$sOriginalClass}{}") ;
}




/**
 * 判断变量的类型
 * PHP的原生函数is_a()只判断对象，JCAT_Global::IsA() 将所有类型和类(class) 同等看待
 * 如果类型 是 类名，则以 is_a（IsKindOf()函数） 判断
 * 
 * @param	$Variable	mixed	待检查的变量名
 * @param	$sType		string	类型
 * @return	void
 */
function IsA($Variable,$sType)
{
	JCAT_ASSERT::ASSERT_STRING($sType) ;
	
	// 整理参数， 以支持  array:xxx 格式 
	$sType = trim($sType) ;
	$arrTypes = explode(':',$sType) ;
	$sRealType = $arrTypes[0] ;
	$sAllow = isset($arrTypes[1])? $arrTypes[1]: null ;
	
	$sRealType = strtolower($sRealType) ;
	
	switch( $sRealType )
	{
		// 字符串
		case 'string' :
			return is_string($Variable) ;
		
		// 整数
		case 'integer' :
		case 'int' :
			return is_int($Variable) ;
			
		// 浮点
		case 'float' :
			return is_float($Variable) ;
			
		// 布尔
		case 'boolean' :
		case 'bool' :
			return is_bool($Variable) ;
			
		// 数字
		case 'num' :
		case 'numeric' :
			return is_numeric($Variable) ;
		
		// 标量（所有基础类型）
		case 'base' :
		case 'scalar' :
			return is_scalar($Variable) ;
		
		// 外部资源
		case 'handle' :
		case 'resource' :
			return is_resource($Variable) ;
		
		// 数组
		case 'array' :
		{
			if( $sAllow )
			{
				$arrAllow = explode(',',$sAllow) ;//print_R($arrAllow) ;
				return CheckArray($Variable,$arrAllow) ;
			}
			else
				return is_array($Variable) ;
		}
		
		// 对象
		case 'object' :
			return is_object($Variable) ;
			
		// 空
		case 'null' :
		case 'NULL' :
			return ($Variable===null) ;
		
		// 回调函数
		case 'callback' :
			return is_callable($Variable) ;
		
		// 类
		default :
			return IsKindOf($Variable,$sType) ;
	}
}

/**
 * 返回变量的类型
 *
 * @param	$Variable
 * @return	string
 */
function GetClass($Variable)
{
	if( is_object($Variable) )
	{
		return get_class($Variable) ;
	}
	
	else if ( is_array($Variable) )
	{
		return 'array' ;
	}
	
	else if ( is_string($Variable) )
	{
		return 'string' ;
	}
	
	else if ( is_numeric($Variable) )
	{
		return 'number' ;
	}
	
	else if ( is_bool($Variable) )
	{
		return 'bool' ;
	}
	
	else if ( is_resource($Variable) )
	{
		return 'handle' ;
	}
	
	else if ( $Variable===null )
	{
		return 'null' ;
	}
	
	else 
	{
		return '??' ;
	}
}

/**
 * 以严格的方式检查数组
 * 
 * @param	$arrArray	array	待检查的数组
 * @param	$arrTypes	array	类型
 * @return	void
 */
function CheckArray( $arrArray,array $arrTypes)
{			
	if( !is_array($arrArray) )
	{
		return false ;
	}
		
	foreach( $arrArray as $Element)
	{
		$bRet = false ;
		foreach($arrTypes as $sType)
		{
			if( IsA($Element,$sType) )
			{
				$bRet = true ;
				break ;
			}
		}
		
		if(!$bRet)
		{
			return false ;
		}
	}
	
	return true ;
}


/**
 * 判断变量 是否符合给定的类型
 * 可以给入多种类型，变量只需符合其中之一。
 * 如果类型 是 类名，则以 is_a（IsKindOf()函数） 判断
 * 
 * @param	$Variable	mixed			待检查的变量名
 * @param	$arrTypes	string,array	必须符合的各项类型
 * @return	void
 */
function IsThese($Variable,$Types)
{
	if( !IsA($Types,'string') and !CheckArray($Types,array('string')) )
	{
		throw new JCAT_Exception( JCAT_Language::SentenceEx('参数 $Types 必须为 string 或 各项元素为string的数组','JCAT',null), JCAT_Exception::MakeExceptionCode(__CLASS__,9) ) ;
	}
	
	if( is_string( $Types ) )
	{
		$arrTypes = array($Types) ;
	}
	else
	{
		$arrTypes = $Types ;
	}
			
	
	// 类型检查
	foreach( $arrTypes as $sType )
	{
		if( IsA($Variable,$sType) )
		{
			return true ;
		}
	}
	
	return false ;
}


/**
 * 将路径整理成统一的格式，斜线方向一致，清除路径中的 “..”、“.” 以及连续“/” ，并且目录统一用“/”（或“\”）结尾
 * 
 * @param	$sPath				string	路径
 * @param	$bUnixStyle=true	bool	返回 Unix 路径风格
 * @return	string
 */
function TidyPath ( $sPath,$bUnixStyle=true)
{
	// 统一 斜线方向
	$sRetPath = str_replace('\\','/',$sPath) ;

	// 归并连续斜线
	$sRetPath = preg_replace('|/+|','/',$sRetPath) ;
	
	// 削除 .. 和  .
	$arrDirs = explode('/',$sRetPath) ;
	$arrDirs2 = array() ;
	//print_r($arrDirs) ;
	while( ($sDirName=array_shift($arrDirs))!==null )
	{
		if($sDirName=='.')
		{
			continue ;
		}
		if($sDirName=='..')
		{
			if( count($arrDirs2) )
			{
				array_pop($arrDirs2) ;
				continue ;
			}
		}
		
		array_push($arrDirs2,$sDirName) ;
	}
	$sRetPath = implode('/',$arrDirs2) ;
	//print_r($arrDirs2) ;
	
	// 目录 以  '/' 结尾
	
	// 存在的目录
	if( is_dir($sRetPath) )
	{
		if( !preg_match('|/$|',$sRetPath) )
		{
			$sRetPath.= '/' ;
		}
	}
	
	// 不存在，但是符合目录的格式
	else if( preg_match("|\.$|",$sPath) )
	{
		if( !preg_match('|/$|',$sRetPath) )
		{
			$sRetPath.= '/' ;
		}
	}
	
	

	// 还原 驱动器符号
	$sRetPath = str_replace(':/',':\\',$sRetPath) ;

	// 转换到 Windows 斜线风格
	if(!$bUnixStyle)
	{
		$sRetPath = str_replace('/','\\',$sRetPath) ;
	}

	return $sRetPath ;
}


/**
 * 返回当前时间（微秒级）
 * 
 * @param	$bExact=true	bool	精确到 微秒，该参数false的话，等同 time()
 * @return	float,int
 */
function Now ( $bExact=true )
{
	if($bExact)
	{
		list($nMS,$nS) = explode(' ',microtime()) ;
		return $nS+$nMS ;
	}
	else
	{
		return time() ;
	}
}

/**
 * 产生乱数字串
 * 
 * @param	$nLength		int			字串長度
 * @param	$sCharBox=null	string,null	可用字符
 * @return	string
 */
function RandString ( $nLength, $sCharBox=null )
{
	if( $sCharBox===null )
	{
		$sBox = strtoupper(md5(Now(true) . rand(1000000000,9999999999))) ;
		$sBox.= md5(Now(true) . rand(1000000000,9999999999)) ;
	}
	else
	{
		$sBox = $sCharBox ;
	}
	
	$n = $nLength ;
	$nBoxEnd = strlen($sBox) - 1 ;
	$sRet = '' ;
	while($n--)
	{
		$sRet.= substr($sBox,rand(0,$nBoxEnd),1) ;
	}

	return $sRet ;
}

	
	
?>